<template>
  <div class="earth-layout">
    <div ref="layerMain" class="layer-main"></div>
    <div ref="mapId" class="earth-style"></div>
  </div>
</template>

<script lang="ts">
import { defineComponent } from 'vue'
import * as THREE from 'three'
import * as TWEEN from '@tweenjs/tween.js'
import { lon2xyz, onPointerMove } from '@/utils/helper'
import EarthImg from '@/assets/images/earth.jpg'
import Diaphragm from '@/assets/images/diaphragm.png'
// eslint-disable-next-line @typescript-eslint/no-unused-vars
import { fnRgbRender } from '@/utils/index'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
import { flyArc } from '@/utils/flyCreate'

let fovState = 100
const radius = 70
let camera: THREE.PerspectiveCamera
const scene = new THREE.Scene()
const group = new THREE.Group()
const renderer = new THREE.WebGLRenderer({
  antialias: true
})
// scene.add(new THREE.AxesHelper(100))
const domElement = renderer.domElement

export default defineComponent({
  name: 'SceneEarth',
  data () {
    return {
      renderer: null,
      mapDom: null,
      animationType: true, // 地球入场动画
      rotationY: false, // 地球自动旋转
      meshAnimateType: false, // 标记点动画
      lonlat: { x: 0, y: 0, z: 200 },
      countryName: null // 数据
    }
  },
  mounted () {
    this.initAllFn()
  },
  methods: {
    initAllFn () {
      this.initThree()
      this.initBall()
      this.initRender()
      domElement.addEventListener('click', event => {
        this.initMouse(event)
      })
      // setTimeout(() => fnRgbRender(scene), 6000)
    },
    initThree () {
      const layer = this.$refs.mapId as HTMLElement
      renderer.setSize(layer.clientWidth, layer.clientHeight)
      renderer.setClearColor(0x000, 0)
      layer.appendChild(renderer.domElement)
      camera = new THREE.PerspectiveCamera(
        fovState,
        layer.clientWidth / layer.clientHeight,
        1,
        1000
      )
      camera.lookAt(0, 0, 0)
      camera.position.set(0, 0, 200)
      // this.$nextTick(() => this.initOrbitControls())
    },
    initBall () {
      const textureLoader = new THREE.TextureLoader()
      // 创建球体
      const geometry = new THREE.SphereGeometry(radius, 100, 100)
      textureLoader.load(EarthImg, function (texture) {
        const material = new THREE.MeshBasicMaterial({
          map: texture // 设置颜色贴图属性值
        })
        // 网格模型对象Mesh
        const mesh = new THREE.Mesh(geometry, material)
        // 唯一标识
        mesh.name = 'ballMain'
        // 添加到场景中
        scene.add(mesh)

        scene.add(flyArc(115.7, 39.56, -77.02238, 38.900042))
        scene.add(flyArc(115.7, 39.56, 139, 35.6))
        scene.add(flyArc(149.130214, -35.318235, -77.02238, 38.900042))
      })
    },
    initRender () {
      renderer.clear()
      // 地球入场动画
      if (this.animationType) this.ballAnimation()
      // 地球旋转
      if (this.rotationY) this.autoRotation()
      // 标记点动画
      if (this.meshAnimateType) this.meshAnimation()
      renderer.render(scene, camera)
      requestAnimationFrame(this.initRender)
      TWEEN.update()
    },
    initOrbitControls () {
      const controls = new OrbitControls(camera, renderer.domElement)
      controls.enableZoom = true
      controls.autoRotate = false
      controls.enablePan = true
      controls.enableDamping = true
      controls.autoRotateSpeed = 2
    },
    ballAnimation () {
      fovState -= 0.6
      camera.fov = fovState
      if (camera.fov <= 60) {
        this.rotationY = true
        this.animationType = false
        this.initOrbitControls()
      } else {
        camera.updateProjectionMatrix()
      }
    },
    autoRotation () {
      scene.rotation.y += 0.003
    },
    meshAnimation () {
      for (const children of group.children) {
        const instance = children as THREE.Mesh
        if (instance.geometry.type === 'PlaneGeometry') {
          // 添加初始随机数，防止动画同步
          (instance.material as THREE.Material).opacity += Math.random() * 0.05
          const opacity = (instance.material as THREE.Material).opacity + 7
          instance.scale.set(opacity, opacity, opacity)
          if (instance.scale.x >= 9) (instance.material as THREE.Material).opacity = 0
        }
      }
    },
    initMouse (event: MouseEvent) {
      event.preventDefault()
      const raycaster = new THREE.Raycaster()
      const state = onPointerMove(event)
      const pointer = new THREE.Vector2(state.x, state.y)
      // 通过摄像机和鼠标位置更新射线
      raycaster.setFromCamera(pointer, camera)
      // 计算物体和射线的焦点
      const intersects = raycaster.intersectObject(group)
      // const intersects = raycaster.intersectObjects(scene.children)

      if (intersects.length < 1) {
        this.rotationY = true
      } else {
        this.moveCameraPos(intersects[0].object)
      }
    },
    initMark (item: any) {
      // const geometry = new THREE.PlaneGeometry(1.5, 1.5) // 默认在XOY平面上
      const geometry = new (THREE as any).PlaneBufferGeometry(1.5, 1.5) // 默认在XOY平面上
      const textureLoader = new THREE.TextureLoader()
      const texture = textureLoader.load(Diaphragm)
      const material = new THREE.MeshBasicMaterial({
        color: item.color,
        map: texture,
        transparent: true,
        opacity: 0,
        side: THREE.DoubleSide
      })
      const mesh = new THREE.Mesh(geometry, material)
      const coord = lon2xyz(radius * 1.01, item.lon, item.lat)
      // mesh.scale.set(2, 2, 2)
      // 唯一标识
      mesh.name = item.name
      // mesh.privateType = 'mark'
      mesh.position.set(coord.x, coord.y, coord.z)
      const coordVec3 = new THREE.Vector3(
        coord.x,
        coord.y,
        coord.z
      ).normalize()
      const meshNormal = new THREE.Vector3(0, 0, 1)
      const layer = scene.getObjectByName(item.name)

      // 四元数属性 .quaternion 表示mesh的角度状态
      // .setFromUnitVectors() 计算两个向量之间构成的四元数值
      mesh.quaternion.setFromUnitVectors(meshNormal, coordVec3)
      if (layer === undefined) {
        group.add(mesh)
        scene.add(group)
        this.meshAnimateType = true
      }
    },
    deleteMark (item: any) {
      // this.frameDivClose()
      for (const children of group.children) {
        if (children.name === item.name) group.remove(children)
      }
    },
    frameDivClose () {
      (this.$refs.layerMain as HTMLElement).style.display = 'none'
    },
    initDivFrame (pointx: number, pointy: number, pointz: number) {
      const Vector = new THREE.Vector3(pointx, pointy, pointz)
      // eslint-disable-next-line @typescript-eslint/no-unused-vars
      const vector = Vector.project(camera)
      // const halfWidth = this.mapDom.offsetWidth / 2
      // const halfHeight = this.mapDom.offsetHeight / 2
      // const x = Math.round(vector.x * halfWidth + halfWidth)
      // const y = Math.round(-vector.y * halfHeight + halfHeight)
      // // 创建div容器
      // const moonDiv = document.getElementById('layerMain')
      // moonDiv.style.display = 'block'
      // moonDiv.style.left = x - 150 + 'px'
      // moonDiv.style.top = y - 180 + 'px'
    },
    initColumn (item: any) {
      if (group.children.length >= 16) return

      const material = new THREE.MeshBasicMaterial({
        color: item.color,
        transparent: true,
        opacity: 0.9,
        side: THREE.DoubleSide
      })
      const coord = lon2xyz(radius * 1.01, item.lon, item.lat)
      const coordVec3 = new THREE.Vector3(coord.x, coord.y, coord.z).normalize()
      const geometry = new THREE.CylinderGeometry(0.2, 2.8, 15)
      const mesh = new THREE.Mesh(geometry, material)
      mesh.name = item.name
      // mesh.privateType = 'column'
      mesh.position.set(coord.x, coord.y, coord.z)
      mesh.quaternion.setFromUnitVectors(new THREE.Vector3(0, 1, 0), coordVec3)
      group.add(mesh)
      scene.add(group)
    },
    // 检索指定的图层
    retrievalLayer (name: string) {
      // 根据指定的name获取对应的对象，总是返回第一个匹配到的对象
      const position = scene.getObjectByName(name)?.position
      if (position) this.initDivFrame(position.x, position.y, position.z)
    },
    moveCameraPos (item: any) {
      const layer = scene.getObjectByName(item.name)
      if (layer) {
        scene.rotation.y = 0
        this.rotationY = false
        new TWEEN.Tween({ x: this.lonlat.x, y: this.lonlat.y, z: this.lonlat.z })
          .to({ x: layer.position.x * 2.8, y: layer.position.y * 2.8, z: layer.position.z * 2.8 }, 1500)
          .onUpdate((position) => {
            camera.lookAt(0, 0, 0)
            camera.position.set(position.x, position.y, position.z)
          })
          .onComplete(() => {
            this.retrievalLayer(item.name)
          })
          .easing(TWEEN.Easing.Sinusoidal.InOut)
          .start()
        this.lonlat = camera.position
        // 弹窗面板赋值
        this.countryName = item.name
      } else {
        console.log(`
        图层数据已被全部删除，请重新刷新界面，
        或者重新调用初始化方法: this.initMap ()
        `)
      }
    },
    setRotationY (value: boolean) {
      this.frameDivClose()
      this.rotationY = value
    },
    delAllState () {
      // this.frameDivClose()
      for (const children of group.children as THREE.Mesh[]) {
        children.geometry.dispose();
        (children.material as THREE.Material).dispose()
        group.remove(children)
      }
      scene.remove(group)
    }
  }
})
</script>

<style scoped lang="scss">
.earth-layout {
  position: relative;
  width: 100%;
  height: 100%;
}

.layer-main {
  position: absolute;
  width: 300px;
  height: 160px;
  line-height: 160px;
  text-align: center;
  color: white;
  display: none;
  background-color: rgba(34, 34, 35, .6);

  .shape {
    position: absolute;
    margin: auto;
    left: 0;
    right: 0;
    width: 0;
    height: 0;
    bottom: -40px;
    border: 20px solid transparent;
    border-top-color: rgba(34, 34, 35, .6);
  }
}

.earth-style {
  overflow: hidden;
  cursor: pointer;
  width: 100%;
  height: 100%;
  box-sizing: border-box;
}
</style>
